/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include <gtest/gtest.h>
#include <internal/bus/bus_hisport/hisport.h>
#include <internal/hasdef.h>
#include <mc/dict.h>

namespace {

class bus_hisport_test : public ::testing::Test {
protected:
    dev::bus_hisport m_bus;

    void SetUp() override {
    }

    void TearDown() override {
    }
};

// 测试构造函数
TEST_F(bus_hisport_test, constructor) {
    dev::bus_hisport bus;
}

// 测试 init 成功（所有字段）
TEST_F(bus_hisport_test, init_success_all_fields) {
    mc::mutable_dict csr_object;
    csr_object["Id"]             = static_cast<uint8_t>(1);
    csr_object["BusNum"]         = static_cast<uint8_t>(128);
    csr_object["RegNum"]         = static_cast<uint8_t>(10);
    csr_object["FlagNum"]        = static_cast<uint8_t>(2);
    csr_object["SendRegAddr"]    = static_cast<uint8_t>(0x00);
    csr_object["RecvRegAddr"]    = static_cast<uint8_t>(0x10);
    csr_object["FlagRegAddr"]    = static_cast<uint8_t>(0x1A);
    csr_object["MaxBatchLen"]    = static_cast<uint8_t>(2);
    csr_object["MaxDataLen"]     = static_cast<uint32_t>(1024);
    csr_object["MaxOffsetWidth"] = static_cast<uint8_t>(2);
    csr_object["MaxLengthWidth"] = static_cast<uint8_t>(2);

    EXPECT_TRUE(m_bus.init(csr_object));
    EXPECT_EQ(m_bus.get_id(), 1);
}

// 测试 init 部分字段
TEST_F(bus_hisport_test, init_partial_fields) {
    mc::mutable_dict csr_object;
    csr_object["Id"] = static_cast<uint8_t>(2);

    EXPECT_TRUE(m_bus.init(csr_object));
    EXPECT_EQ(m_bus.get_id(), 2);
}

// 测试 init 空字典
TEST_F(bus_hisport_test, init_empty_dict) {
    mc::mutable_dict csr_object;
    EXPECT_TRUE(m_bus.init(csr_object));
    csr_object["Id"] = static_cast<uint8_t>(5);
    EXPECT_TRUE(m_bus.init(csr_object));
    EXPECT_EQ(m_bus.get_id(), 5);
}

// 测试 bus_lock 和 bus_unlock
TEST_F(bus_hisport_test, bus_lock_unlock) {
    mc::mutable_dict csr_object;
    csr_object["Id"] = static_cast<uint8_t>(1);
    EXPECT_TRUE(m_bus.init(csr_object));

    EXPECT_NO_THROW(m_bus.bus_lock());
    EXPECT_NO_THROW(m_bus.bus_unlock());
}

// 测试 read offset_width 超出范围
TEST_F(bus_hisport_test, read_invalid_offset_width) {
    mc::mutable_dict csr_object;
    csr_object["Id"] = static_cast<uint8_t>(1);
    EXPECT_TRUE(m_bus.init(csr_object));

    ACCESS_DATA_S data{};
    data.offset_width = 5;  // 超出最大范围4
    data.addr         = 0x70;
    data.offset       = 0x100;
    data.length       = 4;

    EXPECT_THROW(m_bus.read(data), mc::invalid_arg_exception);
}

// 测试 read 成功
TEST_F(bus_hisport_test, read_success) {
    mc::mutable_dict csr_object;
    csr_object["Id"] = static_cast<uint8_t>(1);
    EXPECT_TRUE(m_bus.init(csr_object));

    ACCESS_DATA_S data{};
    data.offset_width = 1;
    data.addr         = 0x70;
    data.offset       = 0x10;
    data.length       = 4;

    uint32_t ret = m_bus.read(data);
    EXPECT_EQ(ret, HAS_OK);
}

// 测试 read 使用扩展读取模式（offset == HISPORT_EXTEND_READ_MODE）
TEST_F(bus_hisport_test, read_extend_mode) {
    mc::mutable_dict csr_object;
    csr_object["Id"] = static_cast<uint8_t>(1);
    EXPECT_TRUE(m_bus.init(csr_object));

    ACCESS_DATA_S data{};
    data.offset_width = 1;
    data.addr         = 0x70;
    data.offset       = 0xFFFFFFFF;  // HISPORT_EXTEND_READ_MODE
    data.length       = 4;
    data.in_buffer    = {0x01, 0x02};

    // 扩展读取模式会先调用 write，然后调用 read
    uint32_t ret = m_bus.read(data);
    EXPECT_EQ(ret, HAS_OK);
}

// 测试 write offset_width 超出范围
TEST_F(bus_hisport_test, write_invalid_offset_width) {
    mc::mutable_dict csr_object;
    csr_object["Id"] = static_cast<uint8_t>(1);
    EXPECT_TRUE(m_bus.init(csr_object));

    ACCESS_DATA_S data{};
    data.offset_width = 5;  // 超出最大范围4
    data.addr         = 0x70;
    data.offset       = 0x100;
    data.length       = 4;
    data.in_buffer    = {0x01, 0x02, 0x03, 0x04};

    EXPECT_THROW(m_bus.write(data), mc::invalid_arg_exception);
}

// 测试 write 成功
TEST_F(bus_hisport_test, write_success) {
    mc::mutable_dict csr_object;
    csr_object["Id"] = static_cast<uint8_t>(1);
    EXPECT_TRUE(m_bus.init(csr_object));

    ACCESS_DATA_S data{};
    data.offset_width = 1;
    data.addr         = 0x70;
    data.offset       = 0x10;
    data.length       = 4;
    data.in_buffer    = {0x01, 0x02, 0x03, 0x04};

    uint32_t ret = m_bus.write(data);
    EXPECT_EQ(ret, HAS_OK);
}

// 测试 init 异常处理
TEST_F(bus_hisport_test, init_exception) {
    mc::mutable_dict csr_object;
    csr_object["Id"] = std::string("invalid");  // 无效类型

    // 应该捕获异常并返回 false
    EXPECT_FALSE(m_bus.init(csr_object));
}

// 测试多次 init
TEST_F(bus_hisport_test, init_multiple_times) {
    mc::mutable_dict csr_object1;
    csr_object1["Id"] = static_cast<uint8_t>(1);
    EXPECT_TRUE(m_bus.init(csr_object1));
    EXPECT_EQ(m_bus.get_id(), 1);

    mc::mutable_dict csr_object2;
    csr_object2["Id"] = static_cast<uint8_t>(2);
    EXPECT_TRUE(m_bus.init(csr_object2));
    EXPECT_EQ(m_bus.get_id(), 2);
}

// 测试不同 offset_width 的 read
TEST_F(bus_hisport_test, read_different_offset_widths) {
    mc::mutable_dict csr_object;
    csr_object["Id"] = static_cast<uint8_t>(1);
    EXPECT_TRUE(m_bus.init(csr_object));

    for (uint8_t offset_width = 0; offset_width <= 4; ++offset_width) {
        ACCESS_DATA_S data{};
        data.offset_width = offset_width;
        data.addr         = 0x70;
        data.offset       = 0x12345678;
        data.length       = 4;

        uint32_t ret = m_bus.read(data);
        EXPECT_EQ(ret, HAS_OK);
    }
}

// 测试不同 offset_width 的 write
TEST_F(bus_hisport_test, write_different_offset_widths) {
    mc::mutable_dict csr_object;
    csr_object["Id"] = static_cast<uint8_t>(1);
    EXPECT_TRUE(m_bus.init(csr_object));

    for (uint8_t offset_width = 0; offset_width <= 4; ++offset_width) {
        ACCESS_DATA_S data{};
        data.offset_width = offset_width;
        data.addr         = 0x70;
        data.offset       = 0x12345678;
        data.length       = 4;
        data.in_buffer    = {0x01, 0x02, 0x03, 0x04};

        uint32_t ret = m_bus.write(data);
        EXPECT_EQ(ret, HAS_OK);
    }
}

// 测试 read 异常处理
TEST_F(bus_hisport_test, read_exception) {
    mc::mutable_dict csr_object;
    csr_object["Id"] = static_cast<uint8_t>(1);
    EXPECT_TRUE(m_bus.init(csr_object));

    ACCESS_DATA_S data{};
    data.offset_width = 1;
    data.addr         = 0x70;
    data.offset       = 0x10;
    data.length       = 4;

    // 由于使用打桩驱动，正常情况下不会抛出异常
    // 但如果驱动抛出异常，应该被捕获并重新抛出
    EXPECT_NO_THROW(m_bus.read(data));
}

// 测试 write 异常处理
TEST_F(bus_hisport_test, write_exception) {
    mc::mutable_dict csr_object;
    csr_object["Id"] = static_cast<uint8_t>(1);
    EXPECT_TRUE(m_bus.init(csr_object));

    ACCESS_DATA_S data{};
    data.offset_width = 1;
    data.addr         = 0x70;
    data.offset       = 0x10;
    data.length       = 4;
    data.in_buffer    = {0x01, 0x02, 0x03, 0x04};

    // 由于使用打桩驱动，正常情况下不会抛出异常
    // 但如果驱动抛出异常，应该被捕获并重新抛出
    EXPECT_NO_THROW(m_bus.write(data));
}

} // namespace

